#pragma once 

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/fcntl.h>
#include <pthread.h>
#include "Task.hpp"
#include "ThreadPool.hpp"

#define DFL_PORT 8081
#define BACKLOG 5

class Prama{
  public:
    int sock;
    std::string ip;
    int port;
  public:
    Prama(int _sock, std::string _ip, int _port)
      :sock(_sock), ip(_ip), port(_port)
    {}

    ~Prama()
    {}

};
class TcpServer
{
  private:
    int port;
    int listen_sock;
    ThreadPool<Task> *tp;
  public:
    TcpServer(int _port = DFL_PORT):port(_port), listen_sock(-1),tp(nullptr)
    {}

    void InitTcpServer()
    {
      listen_sock = socket(AF_INET, SOCK_STREAM, 0);
      if(listen_sock < 0)
      {
        std::cerr << "socket error" << std::endl;
        exit(2);
        //return false;
      }
      struct sockaddr_in local;
      memset(&local, 0, sizeof(local));
      local.sin_family = AF_INET;
      local.sin_port = htons(port);
      local.sin_addr.s_addr = INADDR_ANY;

      if(bind(listen_sock, (struct sockaddr*)&local, sizeof(local)) < 0)
      {
        std::cerr << "bind error" << std::endl;
        exit(3);
        //return false;
      }

      if(listen(listen_sock, BACKLOG) < 0)
      {
        std::cerr << "listen error" << std::endl;
        exit(4);
        //return false;
      }

      tp = new ThreadPool<Task>();
      //return true;
    }

   // static void* HeadlerRequest(void *arg)
   // {
   //   //int sock = *(int*)arg;
   //   Prama *p = (Prama*)arg;
   //   pthread_detach(pthread_self());
   //   
   //   Service(p->sock, p->ip, p->port);
   //   
   //   close(p->sock);
   //   delete  p;
   //   return nullptr;
   // }

    void Loop()
    {
      //signal(SIGCHLD, SIG_IGN);
      tp->InitThreadPool();
      struct sockaddr_in peer;
      for(;;)
      {
        socklen_t  len = sizeof(peer);
        int sock = accept(listen_sock, (struct sockaddr*)&peer, &len);
        if(sock < 0)
        {
          std::cout << "accept error, continue next" << std::endl;
          continue;
        }

        std::string ip = inet_ntoa(peer.sin_addr);
        int port = ntohs(peer.sin_port);
        Task t(sock, ip, port);
        tp->Push(t);

        //pthread_t tid;
        //std::string ip = inet_ntoa(peer.sin_addr);
        //int port = ntohs(peer.sin_port);

        //Prama *p = new Prama(sock, ip, port);
        //pthread_create(&tid, nullptr, HeadlerRequest, p);

        //std::cout << "get a new link: " << sock << std::endl;
      }
    }

    static void Service(int sock, std::string ip, int port)
    {
      char buffer[1024];
      while(true)
      {
        ssize_t size = read(sock, buffer, sizeof(buffer) - 1);
        if(size > 0)
        {
          buffer[size] = 0;
          std::cout << ip << ":" << port << "#" << buffer << std::endl;

          write(sock, buffer, size);
        }
        else if(size == 0)
        {
          std::cout << ip << ":" << port << " close!" << std::endl;
          break;
        }
        else 
        {
          std::cerr << sock << "read error" << std::endl;
          break;
        }
      }
      close(sock);
      std::cout << "service done" << std::endl;
    }

    ~TcpServer()
    {
      if(listen_sock >= 0) close(listen_sock);
    }
};
